#
#      Copyright 2011 Tom Miranda
#       
#       Licensed under the Apache License, Version 2.0 (the "License");
#       you may not use this file except in compliance with the License.
#       You may obtain a copy of the License at
#
#          http://www.apache.org/licenses/LICENSE-2.0
#
#       Unless required by applicable law or agreed to in writing, software
#       distributed under the License is distributed on an "AS IS" BASIS,
#       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#       See the License for the specific language governing permissions and
#       limitations under the License.
#
#	$Id: sageplayer.py 235 2011-09-29 00:34:44Z tom.miranda@gmail.com $

'''A python interface to the Boxee Player class.

This module provides sage-specific functionality to the Boxee Player class.  Specifically it ensures that
playback times are reflected in the Sage database.
'''
import threading, time, mc, recordings
from time import sleep

def play(item, background, api, maxLoadTime=60):
	waits = maxLoadTime
	boxeePlayer = mc.GetPlayer()
	
	# Start the Boxee player.
	sagePlayer = sageplayer(item, background)
	sagePlayer.start()
	sagePlayer.setName('SageBoxeePlayerThread')
	mc.LogDebug("SageBoxee: Created player thread.")
	
	# Wait for the item to load and buffer.
	while (not boxeePlayer.IsPlaying()) and (waits>0):
		mc.LogDebug("SageBoxee: Waiting for item to load.")
		sleep(1)
		waits -= 1
		
	# Make sure it loaded.
	if waits <= 0:
		mc.LogDebug("SageBoxee: Error. item failed to play.")
		return False
		
	# Get the total duration.
	# FIXME - SetDuration is not working in recordings.py.
	#totalDuration = item.GetDuration()
	mediaFileID = item.GetProperty('MediaFileID')
	expr = 'GetAiringDuration(GetMediaFileForID(%s))' % mediaFileID
	totalDuration = api.EvaluateExpression(expr) / 1000
	mc.LogDebug("SageBoxee: Total duration is %s seconds." % totalDuration)
	
	# See how much of this show is already watched.
	expr = 'GetWatchedDuration(GetMediaFileForID(%s))' % mediaFileID
	secsToSkip = api.EvaluateExpression(expr) / 1000
	mc.LogDebug("SageBoxee: Watched duration is %s seconds." % secsToSkip)
	
	# Don't bother skipping if it's very close to the beginning.
	if secsToSkip > 5:
	
		# FIXME - This will not work correctly because Boxee automatically skips over the commercials and doesn't include
		# commercial time as part of the duration.
		
		# If we're at the very end back up to 5 seconds before the end.
		if totalDuration - secsToSkip < 5:
			secsToSkip = totalDuration - 5
		
		# FIXME
		# Sometimes SeekTime() does not work, probably a timing issue.  Put in a small loop to compensate. Still does not
		# work reliably so maybe something else is going on?
		mc.LogDebug("SageBoxee:: Time before skip %s" % mc.GetPlayer().GetTime())
		floatSecs = float(secsToSkip) * 1.0
		mc.LogDebug("SageBoxee: Skipping first %s seconds." % floatSecs)
		waits = 10
		mc.GetPlayer().SeekTime(floatSecs)
		while waits>0 and abs(mc.GetPlayer().GetTime()-floatSecs)>0.5:
			mc.LogDebug("SageBoxee: Failed to seek.  Trying again.")
			waits -= 1
			sleep(0.1)
			floatSecs -= 0.250
			mc.GetPlayer().SeekTime(floatSecs)

		mc.LogDebug("SageBoxee: Time after skip %s" % mc.GetPlayer().GetTime())
		
	# Clear the watched status.
	expr = 'ClearWatched(GetMediaFileForID(%s))' % mediaFileID
	api.EvaluateExpression(expr)
	
	# Wait for playback to stop.
	playbackDuration = 0
	mc.LogDebug("SageBoxee: Waiting for playback to stop.")
	while boxeePlayer.IsPlaying():
		playbackDuration = boxeePlayer.GetTime()
		sleep(1)
	
	durationMillis = long(playbackDuration*1000)
	mc.LogDebug('SageBoxee: Playback duration was %s milliseconds.' % str(durationMillis))
	
	expr = 'SetWatchedTimes(GetMediaFileForID(%s), GetAiringStartTime(GetMediaFileForID(%s))+%s, Time())' % (mediaFileID, mediaFileID, durationMillis)
	api.EvaluateExpression(expr)
	
	# FIXME - Need to SetWatched if we're close to the end.  Not sure how to determine this since Boxee does not count commercials.
	return True
	
def playAll(items, background, api):
	if items==None:
		return
	for item in items:
		mc.LogDebug("SageBoxee: Processing item.")
		if play(item, background, api):
			mc.LogDebug("SageBoxee: Waiting for playback to complete.")
			while mc.GetPlayer().IsPlaying():
				sleep(0.200)
		else:
			mc.LogDebug("SageBoxee: Item did not play.")
	
class sageplayer(threading.Thread):
	_item = None
	_background = False
	_api = None
	_player = None

	def __init__(self, item, background=False):
		threading.Thread.__init__(self)
		self._item = item
		self._background = background
		self._player = mc.GetPlayer()
		
	def run(self):
	
		mc.LogDebug("SageBoxee: sageplayer will play item.")
		
		# Stop anything that may be playing.
		while self._player.IsPlaying():
			mc.LogDebug("SageBoxee: sageplayer stopping currently playing item.")
			self._player.Stop()
			sleep(1)
			
		if int(self._item.GetProperty('NumberOfSegments')) > 1:
			mc.LogDebug("SageBoxee: Playing item with multiple segments.")
			
			# Clear any other playlists
			mc.PlayList(mc.PlayList.PLAYLIST_VIDEO).Clear()
			mc.PlayList(mc.PlayList.PLAYLIST_MUSIC).Clear()
	
			# Create a video playlist.
			playlist = mc.PlayList(mc.PlayList.PLAYLIST_VIDEO)
	
			# Add this item to the playlist and play it.
			playlist = recordings.addMultiSegmentItemToPlaylist(self._item, playlist)
			playlist.Play(0)	
			
		else:
			mc.LogDebug("SageBoxee: Playing item with one segment.")
			if self._background:
				self._player.PlayInBackground(self._item)
			else:
				self._player.Play(self._item)
			
		mc.LogDebug("SageBoxee: sageplayer playback has stopped.")
		return
			